package cn.kevinkun.DragAndDropAlt;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.UsesAssets;
import com.google.appinventor.components.annotations.UsesPermissions;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.AndroidViewComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;
import com.google.appinventor.components.runtime.errors.YailRuntimeError;

import android.view.DragEvent;
import android.view.View;
import android.view.View.DragShadowBuilder;
import android.view.View.OnDragListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;

@DesignerComponent(version = 1, versionName = "1.0", category = ComponentCategory.EXTENSION, description = "Drag and drop a component", iconName = "aiwebres/icon.png", nonVisible = true, helpUrl = "https://kevinkun.cn/draganddrop")
@SimpleObject(external = true)
@UsesAssets(fileNames = "")
@UsesPermissions(permissionNames = "")
public class DragAndDropAlt extends AndroidNonvisibleComponent {

	private String TAG = "DragAndDropAlt";
	private AndroidViewComponent draggedComponent;

	public DragAndDropAlt(ComponentContainer container) {
		super(container.$form());
	}

	@SimpleFunction
	public void SetDroppable(AndroidViewComponent component, boolean enabled) {
		if (!(component instanceof ComponentContainer)) {
			throw new YailRuntimeError("component is not a container", TAG);
		}
		View view = component.getView();
		if (enabled) {

			view.setTag(component);
			view.setOnDragListener(new TestDragListener());
		} else {
			view.setTag(null);
			view.setOnDragListener(null);
		}

	}

	@SimpleFunction
	public void SetDraggable(AndroidViewComponent component, boolean enabled) {
		View view = component.getView();
		if (enabled) {
			view.setOnLongClickListener(new OnLongClickListener() {
				@Override
				public boolean onLongClick(View arg0) {
					draggedComponent = component;
					view.startDragAndDrop(null, new DragShadowBuilder(view), view, 0);
					return false;
				}
			});
		} else {
			view.setOnLongClickListener(null);
		}

	}

	private class TestDragListener implements OnDragListener {

		@Override
		public boolean onDrag(View v, DragEvent event) {
			switch (event.getAction()) {
			case DragEvent.ACTION_DRAG_STARTED:
				DragStarted(draggedComponent);
				break;
			case DragEvent.ACTION_DRAG_ENTERED:
				DragEntered(draggedComponent, (AndroidViewComponent) (v.getTag()));
				break;
			case DragEvent.ACTION_DRAG_LOCATION:
				float x = event.getX();
				float y = event.getY();
				int index = -1;
				AndroidViewComponent target = (AndroidViewComponent) (v.getTag());
				ViewGroup vg = (ViewGroup) ((ViewGroup) v).getChildAt(0);
				for (int i = 0; i < vg.getChildCount(); i++) {
					View child = vg.getChildAt(i);
					if (x > child.getX() && x < child.getX() + child.getWidth() && y > child.getY()
							&& y < child.getY() + child.getHeight()) {
						index = i;
						break;
					}
				}
				DragLocation(draggedComponent, target, index + 1);
				break;
			case DragEvent.ACTION_DRAG_EXITED:
				DragExited(draggedComponent, (AndroidViewComponent) (v.getTag()));
				break;
			case DragEvent.ACTION_DRAG_ENDED:
				DragEnded(draggedComponent, (AndroidViewComponent) (v.getTag()));
				break;
			case DragEvent.ACTION_DROP: {
				float x1 = event.getX();
				float y1 = event.getY();
				int index1 = -1;
				AndroidViewComponent target1 = (AndroidViewComponent) (v.getTag());
				ViewGroup vg1 = (ViewGroup) ((ViewGroup) v).getChildAt(0);
				for (int i = 0; i < vg1.getChildCount(); i++) {
					View child = vg1.getChildAt(i);
					if (x1 > child.getX() && x1 < child.getX() + child.getWidth() && y1 > child.getY()
							&& y1 < child.getY() + child.getHeight()) {
						index1 = i;
						break;
					}
				}
				Drop(draggedComponent, target1, index1 + 1);
			}
				break;
			}
			return true;
		}
	}

	@SimpleEvent
	public void DragStarted(AndroidViewComponent component) {
		EventDispatcher.dispatchEvent(this, "DragStarted", component);
	}

	@SimpleEvent
	public void DragEntered(AndroidViewComponent component, AndroidViewComponent target) {
		EventDispatcher.dispatchEvent(this, "DragEntered", component, target);
	}

	@SimpleEvent
	public void DragLocation(AndroidViewComponent component, AndroidViewComponent target, int index) {
		EventDispatcher.dispatchEvent(this, "DragLocation", component, target, index);
	}

	@SimpleEvent
	public void DragExited(AndroidViewComponent component, AndroidViewComponent target) {
		EventDispatcher.dispatchEvent(this, "DragExited", component, target);
	}

	@SimpleEvent
	public void Drop(AndroidViewComponent component, AndroidViewComponent target, int index) {
		EventDispatcher.dispatchEvent(this, "Drop", component, target, index);
	}

	@SimpleEvent
	public void DragEnded(AndroidViewComponent component, AndroidViewComponent target) {
		EventDispatcher.dispatchEvent(this, "DragEnded", component, target);
	}

	@SimpleFunction(description = "index <=0 for move to end")
	public void MoveComponentTo(AndroidViewComponent component, AndroidViewComponent target, int index) {
		if (!(target instanceof ComponentContainer)) {
			throw new YailRuntimeError("target is not a container", TAG);
		}
		View comp = component.getView();
		((ViewGroup) (comp.getParent())).removeView(comp);

		ViewGroup targ = (ViewGroup) ((ViewGroup) target.getView()).getChildAt(0);
		if (index < 1 || index - 1 > targ.getChildCount()) {
			targ.addView(comp);
		} else {
			targ.addView(comp, index - 1);
		}

	}

}
